import { isArray, isString } from '/@/utils/isUtils'
import { stringUtils } from './stringUtils'
/*
 * @Description: 公共工具类
 * @Author: DHL
 * @Date: 2022-01-01 15:18:18
 * @LastEditors: DHL
 * @LastEditTime: 2022-10-29 23:03:59
 */

import { cloneDeep, remove } from 'lodash-es'

/**
 * 判断是外链
 * @param path
 */
export function isExternal(path: string) {
  return /^(https?:|mailto:|tel:)/.test(path)
}

//////////////////////////////////////////////////
// 数组
//////////////////////////////////////////////////

/**
 * 序列化数组中指定属性
 * @param arr 数组
 * @param key 对象属性名
 * @returns
 */
export function arraySerialize<T>(arr: Array<any>, key: string): Array<T> {
  let rtn: any[] = []
  for (let item of arr) {
    const val = item[key]
    if (val && !rtn.includes(val)) {
      rtn.push(val)
    }
  }
  return rtn
}

/**
 * 序列化数组中指定属性为字符串
 * @param arr 数组
 * @param key 对象属性名
 * @returns
 */
export function arraySerializeToStr(arr: Array<any>, key: string): string {
  return arraySerialize(arr, key).join(',')
}

/**
 * 根据对象属性值，过滤数组
 * @param arr 数组
 * @param propertyName  属性名称
 * @param propertyValue 属性值
 * @param isLike 模糊匹配
 * @returns
 */
export function arrayFilter<T>(
  arr: Array<any>,
  propertyName: string,
  propertyValue: any,
  isLike = false
): Array<T> {
  let rtn: any[] = []
  for (let i = arr.length - 1; i >= 0; i--) {
    if (isLike) {
      if (arr[i][propertyName].indexOf(propertyValue) > -1) {
        rtn.push(arr[i])
      }
    } else {
      if (arr[i][propertyName] == propertyValue) {
        rtn.push(arr[i])
      }
    }
  }
  return rtn
}

/**
 * 删除数组中的某一项
 * @param arr
 * @param node
 */
export function arrayRemoveItem(arr: Array<any>, node: any) {
  const index = arr.indexOf(node)

  if (index > -1) {
    arr.splice(index, 1)
  }
}

/**
 * 根据对象属性值，删除数组
 * @param arr 数组
 * @param propertyName 属性名称
 * @param propertyValue 属性值
 */
export function arrayRemoveByPropertyValue(arr: any[], propertyName: string, propertyValue: any) {
  for (let i = arr.length - 1; i >= 0; i--) {
    if (arr[i][propertyName] == propertyValue) {
      arr.splice(i, 1)
    }
  }
}

/**
 * 获取最后一个值
 * @param arr
 */
export function arrayLastValue(arr: any) {
  if (isString(arr)) {
    return arr
  } else if (isArray(arr)) {
    return arr[arr.length - 1]
  }
  return null
}

//////////////////////////////////////////////////
// tree
//////////////////////////////////////////////////

/**
 * 序列化Tree中指定属性
 * @param arr 数组
 * @param key 对象属性名
 * @returns
 */
export function treeSerialize<T>(tree: Array<any>, key: string): Array<T> {
  let rtn: any[] = []

  const _serialize = (arr: Array<any>) => {
    for (let item of arr) {
      if (item) {
        const val = item[key]
        if (val && !rtn.includes(val)) {
          rtn.push(val)
        }

        if (item.children && item.children.length > 0) {
          _serialize(item.children)
        }
      }
    }
  }

  _serialize(tree)

  return rtn
}

/**
 * list转tree
 *
 * @param list  list集合
 * @param idKey 主键属性名称
 * @param pidKey  父级属性名称
 * @param pidVal  父级值
 */
export function listToTree(
  list: Nullable<Array<any>>,
  idKey: string,
  pidKey: string,
  pidVal: string
) {
  // 树
  let treeList: Array<any> = []

  if (list && list.length > 0) {
    const tempList: any = cloneDeep(list)

    list.forEach((item) => {
      if (stringUtils.isEmpty(pidVal)) {
        pidVal = ''
      }

      if (stringUtils.isEmpty(item[pidKey])) {
        item[pidKey] = ''
      }

      if (item[pidKey] === pidVal) {
        remove(tempList, (n: any) => {
          return n[idKey] === item[idKey]
        })

        const children = listToTree(tempList, idKey, pidKey, item[idKey])
        if (children && children.length > 0) {
          item.children = children
        }

        treeList.push(item)
      }
    })
  }

  return treeList
}

/**
 * 获取父级名称集合
 *
 * @param list  list集合
 * @param idKey 主键属性名称
 * @param pidKey  父级属性名称
 * @param nameKey  获取值属性
 * @param node  父级值
 */
export function getTreeParentName(
  list: Nullable<Array<any>>,
  idKey: string,
  pidKey: string,
  nameKey: string,
  node: any
) {
  let parentNames: Array<string> = []

  if (node && stringUtils.isNotEmpty(node[idKey])) {
    if (stringUtils.isEmpty(node[nameKey]) && list) {
      node = arrayFilter(list, 'id', node[idKey])[0]
    }

    parentNames.unshift(node[nameKey])
    const pidVal = stringUtils.isEmpty(node[pidKey]) ? '' : node[pidKey]
    if (list && list.length > 0) {
      for (let index = 0; index < list.length; index++) {
        const item = list[index]
        if (item[idKey] === pidVal) {
          const rtn = getTreeParentName(list, idKey, pidKey, nameKey, item)
          if (rtn && rtn.length > 0) {
            parentNames.unshift(...rtn)
          }
          break
        }
      }
    }
  }
  return parentNames
}

/**
 * 获取tree选中的节点
 * 因为父级被选中后所有子集都会被选中，所以剔除所有父级节点，只保留子集节点
 * @param list 数据集合
 * @param idKey 主键属性名称
 * @param pidKey  父级属性名称
 * @param pidVal  父级值
 * @param checkKeys  选中key集合
 */
export function getTreeCheckKeys(
  list: Nullable<Array<any>>,
  idKey: string,
  pidKey: string,
  pidVal: string,
  checkKeys: Array<string>
) {
  let isFlag = false

  if (list && list.length > 0) {
    for (const node of list) {
      if (node.checked) {
        checkKeys.push(node[idKey])
      } else {
        arrayRemoveItem(checkKeys, pidVal)
        isFlag = true
      }

      if (node.children && node.children.length > 0) {
        let isRemovePid = getTreeCheckKeys(node.children, idKey, pidKey, node[idKey], checkKeys)

        if (isRemovePid) {
          arrayRemoveItem(checkKeys, pidVal)
        }
      }
    }
  }

  return isFlag
}

//////////////////////////////////////////////////
// HTML
//////////////////////////////////////////////////

/**
 * 获取元素高度
 * @param ele
 * @returns
 */
export function getElementHeight(ele: any) {
  if (!ele) {
    return 0
  }
  return ele.offsetHeight
}
